#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <unordered_map>
#include "Common.hpp"
#include "Log.hpp"

const std::string Sep = "\r\n";
const std::string LineSep = " ";               // 行分隔符
const std::string HeaderLineSep = ":";         // 属性分割符
const std::string BlankLine = Sep;             // 空行
const std::string Http_Version = "Http/1.0";   // Http版本号
const std::string defaulthomepage = "wwwroot"; // 自定义网页根目录
const std::string Page404 = "wwwroot/404.html";
const std::string FirstPage = "index.html"; // 首页
using namespace LogModule;

// B/S模式,浏览器直接当客户端
class HttpRequest
{
public:
    HttpRequest()
    {
    }
    ~HttpRequest()
    {
    }

    // GET /favicon.ico HTTP/1.1
    // Host: 1.12.51.69:8080
    // Connection: keep-alive
    // User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 SLBrowser/9.0.5.12181 SLBChan/105 SLBVPV/64-bit
    // Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
    // Referer: http://1.12.51.69:8080/
    // Accept-Encoding: gzip, deflate
    // Accept-Language: zh-CN,zh;q=0.9
    void Deserialize(std::string &req)
    {
        if (ParseOneLine(req, &_req_line, Sep)) //_req_line被初始化为首行
        {
            ParReqLine(_req_line, Sep); // 从首行中提取内容
        }
        ParseHeader(req); // 提取请求报头
        _body = req;
    }
    void Seturi(const std::string &newuri)
    {
        _uri = newuri;
    }
    std::string Uri()
    {
        return _uri;
    }
    std::string Suffix()
    {
        int pos = _uri.rfind('.');
        std::string suffix = _uri.substr(pos);
        return suffix;
    }
    bool ParseHeader(std::string &request_str)
    {
        std::string line;
        while (true)
        {
            bool r = ParseOneLine(request_str, &line, Sep);
            if (r && !line.empty())
            {
                _req_header.push_back(line);
            }
            else if (r && line.empty()) // 读到了空行
            {
                _blank_line = line;
            }
            else
            {
                return false;
            }
            ParseLineHeaderkv();
        }
    }
    std::string GetContent()
    {
        // std::string content;
        // std::ifstream in(_uri); //以二进制的方式进行读取(因为图片是二进制格式)
        // if (!in.is_open())
        // {
        //     return std::string();
        // }
        // std::string line;
        // while (getline(in, line))
        // {
        //     content += line;
        // }
        // // ifstream析构函数会自动关闭
        // // in.close();
        // return content;

        std::string content;
        std::ifstream in(_uri, std::ios::binary); // 以二进制的方式进行读取(因为图片是二进制格式)
        if (!in.is_open())
        {
            return std::string();
        }
        in.seekg(0, in.end);       // 光标定位到文件末尾
        int filesize = in.tellg(); // 获取光标当前位置(此时光标在文件末尾,也就得到了文件长度)
        in.seekg(0, in.beg);       // 光标回到文件开始,准备进行读取
        content.resize(filesize);
        in.read((char *)content.c_str(), filesize);
        LOG(Loglevel::DEBUG) << "Content lenth:" << content.size();

        return content;
    }
    void Print()
    {
        std::cout << "_method:" << _method << std::endl;
        std::cout << "_uri:" << _uri << std::endl;
        std::cout << "_version:" << _version << std::endl;
        for (auto &line : _req_header)
        {
            std::cout << line << std::endl;
        }
        std::cout << "blankline:" << _blank_line << std::endl;
        std::cout << "body:" << _body << std::endl;
    }

private:
    // 从首行中获取细化后的内容
    void ParReqLine(std::string &_req_line, std::string Sep)
    {
        // 从 HTTP 请求行中提取方法（_method）、URI（_uri）和版本（_version）
        // 并将 _uri 与一个默认主页路径（defaulthomepage）拼接
        (void)Sep;
        std::stringstream ss(_req_line); // 采用流式分隔(空格)
        ss >> _method >> _uri >> _version;
        //
        _uri = defaulthomepage + _uri; // 这样所以路径都是以默认主页路径为根目录了(而不是以服务器的根目录为网页的根目录)
    }
    // 将请求报头内容细化
    void ParseLineHeaderkv()
    {
        std::string key, value;
        for (auto &line : _req_header)
        {
            if (SplitString(line, HeaderLineSep, &key, &value))
            {
                _headerkv.insert(std::make_pair(key, value));
            }
        }
    }
    std::string _req_line;                // 首行
    std::vector<std::string> _req_header; // 请求报头
    std::string _blank_line;              // 空行
    std::string _body;                    // 请求正文
    // 在反序列化过程中细化解析出来的内容
    std::string _method;                                    // 请求方法
    std::string _uri;                                       // 统一资源描述符
    std::string _version;                                   // http版本
    std::unordered_map<std::string, std::string> _headerkv; // 参数
};
class HttpResponse
{
public:
    HttpResponse()
        : _version(Http_Version), _blank_line(Sep)
    {
    }
    ~HttpResponse()
    {
    }
    void Build(HttpRequest &req)
    {
        std::string uri = req.Uri(); // 1.wwwroot/ 2.wwwroot/a/b/
        if (uri.back() == '/')       // 1.默认访问首页
        {
            uri += FirstPage;
            req.Seturi(uri);
        }
        _content = req.GetContent();
        if (_content.empty())
        {
            _status_code = 404;
            req.Seturi(Page404);
            _content = req.GetContent();
        }
        else
        {
            _status_code = 200;
        }
        LOG(Loglevel::DEBUG) << "客户正在请求:" << req.Uri();
        _status_des = Code2Des(_status_code);
        // 在构建时就把响应报头的参数填进容器里
        if (!_content.empty())
        {
            SetHeaderkv("Content-Length", std::to_string(_content.size()));
        }
        std::string mime_types = req.Suffix();
        LOG(Loglevel::DEBUG) << "MIME:" << mime_types;
        SetHeaderkv("Content-Type", mime_types);
        for (auto &header : _headerkv)
        {
            _res_header.push_back(header.first + HeaderLineSep + header.second);
        }
    }
    void Serialize(std::string *resp_str)
    {
        // 首行: 版本+ 空格 + 状态码 + 空格 + 状态码描述 + 换行符
        _res_line = _version + LineSep + std::to_string(_status_code) + LineSep + _status_des + Sep;
        _body = _content;
        *resp_str = _res_line;
        for (auto &line : _res_header)
        {
            *resp_str += (line + Sep);
        }
        *resp_str += _blank_line;
        *resp_str += _body;
    }

private:
    std::string Code2Des(int status_code)
    {
        switch (status_code)
        {
        case 200:
        {
            return "OK";
        }
        case 404:
        {
            return "Not Found";
        }
        default:
        {
            return std::string();
        }
        }
    }
    // 根据后缀获取文件MIME类型,从而根据文件格式正确解析
    std::string Suffix2Desc(const std::string &suffix)
    {
        if (suffix == ".html")
        {
            return "text/html";
        }
        else if (suffix == ".png")
        {
            return "image/png";
        }
        else
        {
            return "text/html";
        }
    }
    void SetHeaderkv(const std::string &key, const std::string &value)
    {
        _headerkv[key] = value;
    }
    std::string _version;
    int _status_code;        // 状态码
    std::string _status_des; // 状态码描述
    std::unordered_map<std::string, std::string> _headerkv;

    std::string _res_line;                // 首行
    std::vector<std::string> _res_header; // 响应报头
    std::string _blank_line;
    std::string _body;
    std::string _content;
};